// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
use crate::*;
use anyhow::anyhow;
use chatdb::{read_last_chats, save_chat2db, ChatHistory};
use chrono::Local;
use common::*;
use reqwest::header::HeaderMap;
use serde::de;
use tauri_plugin_store::StoreExt;
use tracing_subscriber::fmt::format;
use std::collections::HashMap;
use std::io::{BufRead, BufReader};
use std::ops::Sub;
use std::path::{self, Path};
use std::sync::Arc;
use std::vec;
use tauri_plugin_notification::NotificationExt;
use tracing::{debug, error, info};
use anyhow::{bail};
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogKind};
use tauri::path::BaseDirectory;
use tauri::{Emitter, ipc::Channel};

type SharedState = Arc<Shared>;

#[tauri::command]
pub async fn grep_hello(name: String) -> Result<HashMap<String, Vec<grep_result> >, String> {   
    debug!("{}", name);
    let source_path = "./";      
    let files = collect_files(source_path, "rs,md,txt.js").unwrap_or_default();   
    match grep_file(&files, &name) {
        Ok(res) => {
            debug!("file list:\n{:#?}\n grep result:\n {:#?}", files, res);
            return Ok(res);        
        },
        Err(er) => {
            error!("grep_file error: {}", er);
        }            
    }
    return Err("grep_file error".to_string());    
}


#[tauri::command]
pub async fn send_channel_abc(app: tauri::AppHandle, on_event: Channel<SubFutureInfo>) -> Result<String, String> {        
    on_event.send( SubFutureInfo{ code:"AB".to_owned(), addr:"128.0.0.1:4500".to_owned()}).unwrap();
    Ok("channel test".to_owned())
}


#[tauri::command]
pub async fn send_emit_abc(app: tauri::AppHandle) -> Result<String, String> {
        
    app.emit("hello", &SubFutureInfo{ code:"AP".to_owned(), addr:"128.0.0.1:4500".to_owned() } ).unwrap();
    Ok("emit test".to_owned())
}


#[tauri::command]
pub async fn get_ask_dialog(app: tauri::AppHandle) -> Result<String, String> {
    app.dialog()
        .message("Tauri is Awesome")
        .title("Tauri is Awesome")
        .buttons(MessageDialogButtons::YesNo)
        .show(|result| match result {
            true => {
                info!("User clicked yes");
            }
            false => {
                info!("User clicked no");
            }
        });
    Ok("ask Dialog".to_owned())
}

#[tauri::command]
pub async fn get_msg_dialog(app: tauri::AppHandle) -> Result<String, String> {
    app.dialog()
        .message("Tauri is Awesome")
        .title("Information")
        .kind(MessageDialogKind::Warning)
        .show(|result| match result {
            true => {
                info!("User clicked yes");
            }
            false => {
                info!("User clicked no");
            }
        });
    Ok("msg Dialog".to_owned())
}

#[tauri::command]
pub async fn get_file_dialog(app: tauri::AppHandle) -> Result<String, String> {
    let ans = app
        .dialog()
        .file()
        .add_filter("My Filter", &["png", "jpeg"])
        .pick_file(|file_path| {
            info!("Selected file: {:?}", file_path);
            // return a file_path `Option`, or `None` if the user closes the dialog
        });
    Ok("file Dialog".to_owned())
}

#[tauri::command]
pub async fn show_notify(app: tauri::AppHandle) -> Result<String, String> {
    let ans = app
        .notification()
        .builder()
        .title("This is a notification")
        .body("This is the body")
        .show();
    Ok("notify test".to_owned())
}

#[tauri::command]
pub async fn store_abc(app: tauri::AppHandle) -> Result<String, String> {
    let store = if let Some(s) = app.get_store("store.bin") {
        s
      }else{
        error!("store.bin not found");
        return Err("store.bin not found".to_owned()); 
      };

      store.set("some-key".to_string(), json!({ "value": 5 }));
      // 从 Store 中获取一个值。
      let value = store.get("some-key").expect("Failed to get value from store");
      debug!("{}", value); // {"value":5}   

      let _t = app
      .notification()
      .builder()
      .title("This is a notification")
      .body( format!("{:?}", value))
      .show();

    Ok("store test".to_owned())
}


#[tauri::command]
pub async fn resource_abc(app: tauri::AppHandle) -> Result<String, String> {
    /* 
    //1. tauri.conf.json 配置
     "bundle": {  
        "resources": [      
            "conf/yeeapp.json"
        ]
    }
    //2. conf/yeeapp.json 位置
    与tauri.conf.json 同级目录下，
    //3. 读取文件
    let resource_path = app.path().resolve("conf/yeeapp.json", BaseDirectory::Resource);    
    */
    
    let resource_path = if let Ok(rpth) = app.path().resolve("conf/yeeapp.json", BaseDirectory::Resource){ rpth}else{
        return Err("resource path not found".to_owned());
    };
    let file = std::fs::File::open(&resource_path).unwrap();
    let cfg: serde_json::Value = serde_json::from_reader(file).unwrap();
    
    println!("{:?}", cfg );
    Ok("resource file test".to_owned())
}

#[tauri::command]
pub async fn get_futures(
    state: tauri::State<'_, SharedState>,
) -> Result<HashMap<String, Vec<SubFutureInfo>>, String> {
    // State抽取案例，同步不可以！
    let dict = state.cfg.futures.clone();
    //let src = serde_json::to_string(&dict).unwrap();
    //Ok(src)
    Ok(dict)
}

#[tauri::command]
pub async fn chat_chat(name: String,
    state: tauri::State<'_, SharedState>,
) -> Result<Vec<ChatHistory>, String> {
    // State抽取案例，同步不可以！
    debug!("chat_chat: {}", name);
    if name.len() > 0 { 
        let resp = chat_with_glm_response(&name).await;              
        let st = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();     
        let r = save_chat2db(&state.dbpool, &name, &st, &resp).await;
        if let Err(er) = r {
            error!("save_chat2db error: {}", er);
        }   
    }
    let retv = read_last_chats( &state.dbpool, 10).await.unwrap();        
    Ok(retv)   
}

/**
 * server: 8.155.160.209:9995, www.mark.lengsh.cn:[9995, 9994],
 */
pub async fn get_tradedays_from_yee(server: &str) -> anyhow::Result<Vec<String>> {
    let client = reqwest::Client::new();

    let api = if server.starts_with("http") {
        format!("{}/yee/api/tradedays", server)
    } else {
        format!("http://{}/yee/api/tradedays", server)
    };

    let mut headers = HeaderMap::new();
    // headers.insert("Authorization", "Bearer xman".parse()?);
    headers.insert("Content-Type", "application/json; charset=utf-8".parse()?);

    let r: Vec<String> = client
        .get(&api)
        .headers(headers)
        .send()
        .await?
        .json()
        .await?;
    // debug!("{:#?}", r);
    return Ok(r);
}

pub async fn chat_with_glm_response(msg: &str) -> String {
    match chat_with_glm(msg).await{
      anyhow::Result::Ok(rs) =>      
        if rs.choices.len() > 0 {
          if rs.choices.len() > 1 {
              error!("response msg is more than 1, but only use the first one now!");
          }
          let choice = rs.choices[0].clone();
          let content = choice.message.content;
          return content;
        }else{
          return "".to_string();
        },
      Err(er)=> {
        error!("error {:?} ", er);
        return "".to_string();
      },
    }
  }
  
  /**
   * 简单调用GLM开方接口，采用glm-4-flash模型，进行对话。
   */
  pub async fn chat_with_glm(msg: &str) -> anyhow::Result<GlmResponse> {
      if msg.is_empty(){
        bail!("msg is empty");
      }
      let client = reqwest::Client::new();
      let api = "https://open.bigmodel.cn/api/paas/v4/chat/completions";
  
      let mut headers = HeaderMap::new();
      headers.insert(
          "Authorization",
          "Bearer efee28671779b38ba107b5a8f89491cc.V2R8xEzrqo5FG8RT".parse()?,
      );
      headers.insert("Content-Type", "application/json; charset=utf-8".parse()?);
  
      let messages = vec![GlmMessage {
          role: "user".to_string(),
          content: msg.to_string(),
      }];
  
      // logging::log!("{:#?}", messages);
  
      let askmsg: GlmRequestParam = GlmRequestParam {
          model: "glm-4-flash".to_string(),
          messages,
          temperature: 0.9,
      };
  
      let r: GlmResponse = client
          .post(api)
          .headers(headers)
          .json(&askmsg)
          .send()
          .await?
          .json()
          .await?;
      // logging::log!("{:#?}", r);
      return Ok(r);
  }
  